package com.ms.jsf.aop;

import com.ms.exception.DpwcException;
import com.ms.exception.DpwcSystemException;
import com.ms.jsf.FindCrudBeanBase;
import com.ms.jsf.JsfBeanBase;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;

@Aspect
@Component("jsfBeanAspect")
public class JsfBeanAspect {
    protected final Logger LOG = LoggerFactory.getLogger(getClass());

    @PostConstruct
    public void init(){
//        System.out.println("xxx");
    }

    @Pointcut("bean(*JsfBean)")
    private void jsfBean() {
    }

    @Pointcut("execution(public * *Action())")
    private void publicMethodThatItsNameEndWithAction() {
    }

    @Pointcut("execution(public * *(javax.faces.event.ActionEvent))")
    private void publicMethodActionEvent() {
    }

    @Pointcut("execution(public * *(org.primefaces.event.RowEditEvent))")
    private void publicMethodRowEditEvent() {
    }

    @Pointcut("execution(public * *(org.primefaces.event.FileUploadEvent))")
    private void publicMethodFileUploadEvent() {
    }

    @Pointcut("execution(public * *(org.primefaces.event.SelectEvent))")
    private void publicMethodSelectEvent() {
    }

    @Pointcut("execution(public * *(org.primefaces.event.ScheduleEntryMoveEvent))")
    private void publicMethodScheduleEntryMoveEvent() {
    }

    @Before("jsfBean() && args(actionEvent)")
    @Order(1)
    public void processJsfBeanBeforeMethods(JoinPoint joinPoint,
                                            ActionEvent actionEvent) {
        Object target = joinPoint.getTarget();
        if (target instanceof JsfBeanBase) {
            JsfBeanBase jsfBeanBase = (JsfBeanBase) target;
            jsfBeanBase.setActionEvent(actionEvent);
        }
    }

    @Around("jsfBean() && ( publicMethodThatItsNameEndWithAction() " +
            "|| publicMethodActionEvent() " +
            "|| publicMethodFileUploadEvent() " +
            "|| publicMethodSelectEvent() " +
            "|| publicMethodScheduleEntryMoveEvent()" +
            "|| publicMethodRowEditEvent() )")
    @Order(2)
    public Object processJsfBeanMethods(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        String method = proceedingJoinPoint.getSignature().toShortString();
        try {
            FacesContext facesContext = FacesContext.getCurrentInstance();
            if (facesContext.isValidationFailed()) {
                LOG.error("There are validation problems. The method:" + method + " will not be executed.");
                return null;
            }
            LOG.debug("Around: Before executing:" + method);
            Object obj = proceedingJoinPoint.proceed();
            LOG.debug("Around: After executing:" + method);
            return obj;
        } catch (Throwable throwable) {
            LOG.error("Problemas llamado al metodo: " + method, throwable);
            Object target = proceedingJoinPoint.getTarget();
            if (target instanceof JsfBeanBase) {
                JsfBeanBase jsfBeanBase = (JsfBeanBase) target;
                FacesContext facesContext = FacesContext.getCurrentInstance();
                facesContext.validationFailed();
                if (throwable instanceof DpwcException) {
                    if (throwable instanceof DpwcSystemException) {
                        jsfBeanBase.addFatalDpwcErrorMessage((DpwcSystemException)throwable);
                    }else {
                        DpwcException dpwcException = (DpwcException) throwable;
                        if(dpwcException.getCause()==null){
                            jsfBeanBase.addErrorMessage(dpwcException);
                        }else {
                            jsfBeanBase.addErrorMessageWithDetails(dpwcException);
                        }
                    }
                } else {
                    jsfBeanBase.addFatalErrorMessage(throwable);
                }
            }
            return null;
        } finally {
            Object target = proceedingJoinPoint.getTarget();
            if (target instanceof FindCrudBeanBase) {
                FindCrudBeanBase findCrudBeanBase = (FindCrudBeanBase) target;
                findCrudBeanBase.setSelectedRow(null);
            }
        }
    }
}